﻿using MyFloridaHouse.libSvOpenDistricts.PDF;
using System;
using System.IO;
using C1.Silverlight.Pdf;
using MyFloridaHouse.libSvDTO;
using MyFloridaHouse.libSvUtilities.Logging;
using MyFloridaHouse.libSvOpenDistricts.StorageIsolated;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using MyFloridaHouse.libSvOpenDistricts.Dialogs;

namespace MyFloridaHouse.libSvOpenDistricts.ViewModel
{
    public partial class ViewModelBase
    {
        private PDFErrorDlg pdfErrorDlg;

        private bool _isPDFViewVisible = false;
        public bool isPDFViewVisible
        {
            get { return _isPDFViewVisible; }
            set { if (_isPDFViewVisible != value) { _isPDFViewVisible = value; NotifyPropertyChanged("isPDFViewVisible"); } }
        }

        private HouseMap _doc;
        public HouseMap doc
        {
            get { return _doc; }
            set { if (_doc != value) { _doc = value; NotifyPropertyChanged("doc"); } }
        }


        public void PDFOpenViewer()
        {
            isPDFViewVisible = true;
            PDFdocEvents.PDFMapComplete += OnPDFMapComplete;
            ClearMap();

        }

        public void PDFClose()
        {
            isPDFViewVisible = false;
            PDFdocEvents.PDFMapComplete -= OnPDFMapComplete;
            doc = null;
        }

        private void ClearMap()
        {
            C1PdfDocument pdf = new C1PdfDocument();
            MemoryStream pdfStream = new MemoryStream();

            pdf.Save(pdfStream);
            pdfStream.Seek(0, SeekOrigin.Begin);
        }

        public void OnPDFMapComplete(object sender, PDFMapCompleteEventArgs args)
        {
            isPDFViewVisible = false;
            if (!args.IsSuccess)
            {
                ShowPDFErrorDlg();
            }
            else
            {
                PDFSaveDlg pdfSaveDlg = new PDFSaveDlg(OnMemberPropertyChanged, DisplayPanelForDialogs);
                pdfSaveDlg.Start(PDFSaveFile);
            }
        }

        private void ShowPDFErrorDlg()
        {
            if (null == pdfErrorDlg)
            {
                pdfErrorDlg = new PDFErrorDlg(OnMemberPropertyChanged, DisplayPanelForDialogs);
                pdfErrorDlg.Start(PDFErrorComplete);
            }
        }

       
        public void PDFErrorComplete(bool success)
        {
            pdfErrorDlg = null;
        }

        public void PDFSaveFile(bool success)
        {
            if (!success)
            {
                byte[] fileBytes = doc.ToPDF().ToArray();
                PDFClose();
            }
            else
            {
                byte[] fileBytes = doc.ToPDF().ToArray();
                PDFClose();
                try
                {
                    SaveFileDialog saveFileDlg = new SaveFileDialog();
                    saveFileDlg.Filter = "PDF files (*.pdf)|*.pdf";
                    bool? dialogResult = saveFileDlg.ShowDialog();
                    if (dialogResult == true)
                    {
                        using (var fs = saveFileDlg.OpenFile())
                        {
                            fs.Write(fileBytes, 0, fileBytes.Length);
                            fs.Close();
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.HandleInternalError(string.Format("Unable to save file: {0}", ex.Message));
                }
            }
        }

        internal void DistrictPlanPDFPrint(string title, BoundingBoxDTO currentViewBoundingBoxLatLon, enumDistrictPlanPDFPrintSizes printSize, enumDistrictPlanPDFPrintMapAreas mapArea, int districtID)
        {
            try
            {
                PDFOpenViewer();
                switch (mapArea)
                {
                    case enumDistrictPlanPDFPrintMapAreas.DISTRICT:
                        doc = new HouseMapLayoutDistrict(new PDF_DAL(serviceDAL), printSize, districtPlan, title, districtID);
                        break;
                    case enumDistrictPlanPDFPrintMapAreas.STATE:
                        doc = new HouseMapLayoutState(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                        break;
                    case enumDistrictPlanPDFPrintMapAreas.CURRENTVIEW:
                        doc = new HouseMapLayoutCurrentView(new PDF_DAL(serviceDAL), printSize, districtPlan, title, currentViewBoundingBoxLatLon);
                        break;
                    case enumDistrictPlanPDFPrintMapAreas.REGIONAL:
                        doc = GeneratePDFDocRegional(title, printSize, districtPlanPrintPdfDlg.PDFregionListSelectedValue);
                        break;
                    default:
                        throw new Exception("Invalid print area selection, unable to continue printing");
                }
            }
            catch (Exception ex)
            {
                PDFClose();
                throw ex;
            }
        }

        private HouseMap GeneratePDFDocRegional(string title, enumDistrictPlanPDFPrintSizes printSize, enumHouseMapRegions region)
        {
            HouseMap newHouseMap = null;

            switch (region)
            {
                case enumHouseMapRegions.Northwest:
                    newHouseMap = new HouseMapLayoutRegionalNorthwest(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.BigBend:
                    newHouseMap = new HouseMapLayoutRegionalBigBend(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.Northeast:
                    newHouseMap = new HouseMapLayoutRegionalNortheast(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.CentralNorth:
                    newHouseMap = new HouseMapLayoutRegionalCentralNorth(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.CentralSouth:
                    newHouseMap = new HouseMapLayoutRegionalCentralSouth(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.Southeast:
                    newHouseMap = new HouseMapLayoutRegionalSoutheast(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.South:
                    newHouseMap = new HouseMapLayoutRegionalSouth(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.TampaBay:
                    newHouseMap = new HouseMapLayoutRegionalTampaBay(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                case enumHouseMapRegions.MiamiDade:
                    newHouseMap = new HouseMapLayoutRegionalMiamiDade(new PDF_DAL(serviceDAL), printSize, districtPlan, title);
                    break;
                default:
                    throw new Exception("Invalid print region selection, unable to continue printing");
            }

            return newHouseMap;
        }


        // *** BATCH PDF

        const string IsolatedStorageBatchPDFDirectory = "BatchPDF";
        private int pdfBatchFailureCount = 0;

        private int _PDFBatchCount = 0;
        public int PDFBatchCount
        {
            get { return _PDFBatchCount; }
            set { if (_PDFBatchCount != value) { _PDFBatchCount = value; NotifyPropertyChanged("PDFBatchCount"); } }
        }

        private string _PDFBatchFileName = "Not Specified";
        public string PDFBatchFileName
        {
            get { return _PDFBatchFileName; }
            set { if (_PDFBatchFileName != value) { _PDFBatchFileName = value; NotifyPropertyChanged("PDFBatchFileName"); } }
        }

        private ObservableCollection<string> _PDFstatusList = new ObservableCollection<string>();
        public ObservableCollection<string> PDFstatusList
        {
            get { return _PDFstatusList; }
            set { if (_PDFstatusList != value) { _PDFstatusList = value; NotifyPropertyChanged("PDFstatusList"); } }
        }

        List<HouseMapRequest> requestList = new List<HouseMapRequest>();

        public void BatchPDFClose()
        {
            requestList.Clear();
            PDFBatchCount = 0;
            PDFdocEvents.UnsubscribePDFMapComplete();
        }

        internal void BatchPDFPrint(string title, string fileRoot)
        {
            try
            {
                pdfBatchFailureCount = 0;
                requestList.Clear();
                PDFstatusList.Clear();
                PDFdocEvents.UnsubscribePDFMapComplete();
                PDFdocEvents.PDFMapComplete += OnBatchPDFMapComplete;

                enumDistrictPlanPDFPrintSizes printSize = enumDistrictPlanPDFPrintSizes._32x32;
                for (int i = 0; i <= 1; i++)
                {
                    if (i != 0)
                    {
                        printSize = enumDistrictPlanPDFPrintSizes._8x11;
                    }

                    //districts
                    foreach (var district in districtPlan.districtList)
                    {
                        if (district.districtMultiMapShape.Vertices.Count > 0)
                        {
                            requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.DISTRICT, printSize, districtPlan, title, fileRoot + "_District_" + district.districtID.ToString("000") + printSize.ToString() + ".pdf", district.districtID));
                            PDFBatchCount++;
                        }
                    }

                    //regions
                    // todo: Should make this loop through the enumeration
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.Northwest.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.Northwest));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.BigBend.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.BigBend));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.Northeast.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.Northeast));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.CentralNorth.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.CentralNorth));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.CentralSouth.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.CentralSouth));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.Southeast.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.Southeast));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.South.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.South));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.TampaBay.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.TampaBay));
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.REGIONAL, printSize, districtPlan, title, fileRoot + "_Regional_" + enumHouseMapRegions.MiamiDade.ToString() + printSize.ToString() + ".pdf", enumHouseMapRegions.MiamiDade));

                    //state
                    requestList.Add(new HouseMapRequest(enumDistrictPlanPDFPrintMapAreas.STATE, printSize, districtPlan, title, fileRoot + "_State" + printSize.ToString() + ".pdf"));
                    PDFBatchCount++;
                }

                // kick off the pdf generation
                PDFBatchCount = requestList.Count;

                BatchPDFStartNextFile();
                
                return;
            }
            catch (Exception ex)
            {
                requestList.Clear();
                throw ex;
            }

        }

        const string PDFIsolatedStorageDirectory = "BatchPDF";
        const int MaxPDFBatchErrorCount = 2;
        public void IncreaseIsolatedStorage()
        {
            // don't just save enough for this file, try to get enough for all remaining
            // estimate average of 4 MB per file
            int MBtoReserve = PDFBatchCount * 4;

            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForSite())
            {
                Int64 bytesToReserve = MBtoReserve * 1000000;
                Int64 currAval = isf.AvailableFreeSpace;
                if (currAval < bytesToReserve)
                {
                    PDFstatusList.Insert(0, "..... Reserving " + MBtoReserve.ToString() + "M of isolated storage space");
                    IsolatedStorageIncreaseOnlyDlgWindow dlg = new IsolatedStorageIncreaseOnlyDlgWindow(bytesToReserve);
                    dlg.Show();
                    dlg.Closed += new EventHandler(onIsolatedStorageIncreaseOnlyDlgClosedEventHandler);
                }
                isf.Dispose();
            }
        }


        public void onIsolatedStorageIncreaseOnlyDlgClosedEventHandler(object sender, EventArgs args)
        {
            IsolatedStorageIncreaseOnlyDlgWindow dlg = (IsolatedStorageIncreaseOnlyDlgWindow)sender;
            dlg.Closed -= new EventHandler(onIsolatedStorageIncreaseOnlyDlgClosedEventHandler);

            if (!(bool)dlg.DialogResult)
            {
                PDFstatusList.Insert(0, "*** Error Reserving isolated storage space");
                Log.NotifyUser("Unable to increase isolated storage - Batch PDF generation will not work");
                BatchPDFClose();
                return;
            }
            OnBatchPDFMapComplete(this, new PDFMapCompleteEventArgs(true));

        }

        public void OnBatchPDFMapComplete(object sender, PDFMapCompleteEventArgs args)
        {

            if (null != doc)
            {
                PDFstatusList.Insert(0, "["+ PDFBatchCount.ToString() + "] " + "... Map Generation complete");

                if (PDFBatchCount > 0)
                {
                    if (!args.IsSuccess)
                    {
                        PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + "............ MAP GENERATION FAILED");
                        ShowPDFErrorDlg();
                        if (++pdfBatchFailureCount > MaxPDFBatchErrorCount)
                        {
                            BatchPDFClose();
                        }
                        else
                        {
                            PDFBatchCount--;
                        }
                        
                    }
                    else
                    {
                        var currentMapRequest = requestList[PDFBatchCount - 1];
                        try
                        {
                            PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + ".... Attempting save for " + currentMapRequest.filename);

                            MemoryStream pdfStream = doc.ToPDF();
                            doc = null;

                            if (!IsolatedStorageManager.CheckStorageSize(pdfStream.Length))
                            {
                                PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + "***** No space available for " + currentMapRequest.filename + "; requesting space increase");
                                IncreaseIsolatedStorage();
                                return;
                            }

                            try
                            {
                                IsolatedStorageManager.Deletefile(PDFIsolatedStorageDirectory, currentMapRequest.filename);
                            }
                            catch (Exception ex)
                            {
                                // ignore
                            }
                            if (!IsolatedStorageManager.SaveData(pdfStream.ToArray(), PDFIsolatedStorageDirectory, currentMapRequest.filename))
                            {
                                Log.NotifyUser("Error writing " + currentMapRequest.filename + " to Isolated Storage");
                                BatchPDFClose();
                            }

                            PDFBatchCount--;
                        }

                        catch (Exception ex)
                        {
                            Log.NotifyUser("Error saving file for " + currentMapRequest.filename + "; " + ex.Message);
                            BatchPDFClose();
                        }
                    }
                }
            }

            BatchPDFStartNextFile();

           
        }

        private void BatchPDFStartNextFile()
        {

            if (PDFBatchCount > 0)
            {

                var currentMapRequest = requestList[PDFBatchCount - 1];
                PDFstatusList.Insert(0, " ");

                try
                {
                    switch (currentMapRequest.requestType)
                    {

                        case enumDistrictPlanPDFPrintMapAreas.DISTRICT:
                            PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + ".. Generating PDF for " + currentMapRequest.filename);
                            doc = new HouseMapLayoutDistrict(new PDF_DAL(serviceDAL), currentMapRequest.printSize, districtPlan, currentMapRequest.title, currentMapRequest.districtID);
                            break;
                        case enumDistrictPlanPDFPrintMapAreas.STATE:
                            PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + ".. Generating PDF for " + currentMapRequest.filename);
                            doc = new HouseMapLayoutState(new PDF_DAL(serviceDAL), currentMapRequest.printSize, districtPlan, currentMapRequest.title);
                            break;
                        case enumDistrictPlanPDFPrintMapAreas.REGIONAL:
                            PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + ".. Generating PDF for " + currentMapRequest.filename);
                            doc = GeneratePDFDocRegional(currentMapRequest.title, currentMapRequest.printSize, currentMapRequest.region);
                            break;
                        default:
                            PDFstatusList.Insert(0, "[" + PDFBatchCount.ToString() + "] " + ".. Invalid type for " + currentMapRequest.filename);
                            throw new Exception("Invalid print area selection, unable to continue printing");
                    }
                }
                catch (Exception ex)
                {
                    Log.NotifyUser("Error generating " + currentMapRequest.filename + "; " + ex.Message);
                    BatchPDFClose();
                }
            }
            else
            {
                // generation is complete
                BatchPDFClose();
            }
        }

    }


    
}
